﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;
using SignalR通讯.Models;
using Model;
using SignalR通讯.PublicTool;

namespace SignalR通讯
{
    public class ServerHub : Hub
    {
        #region 暂时无用 

        //暂时无用
        public static List<UserInfo> OnlineUsers = new List<UserInfo>(); // 在线用户列表

        //暂时无用
        private static readonly char[] Constant =
        {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
            'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
            'W', 'X', 'Y', 'Z'
        };

        #endregion

        #region 客户端连接的时候调用

        /// <summary>
        /// 客户端连接的时候调用
        /// </summary>
        /// <returns></returns>
        public override Task OnConnected()
        {
            // 查询用户  并把连接id ConnectionId的值,赋值给userid 
            var user = DbContext.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId);

            if (user == null)
            {
                user = new UserGroup
                {
                    UserId = Context.ConnectionId
                };

                DbContext.Users.Add(user);
            }

            // 发送房间列表
            var items = DbContext.Rooms.Select(p => new { p.RoomName });
            Clients.Client(this.Context.ConnectionId).getRoomList(JsonHelper.ToJsonString(items.ToList()));

            Trace.WriteLine("客户端连接成功");
            return base.OnConnected();
        }

        #endregion

        #region 发送所有人

        /// <summary>
        /// 前端调用  PrivateSend 开始字母必须小写  sendPrivateMessage 同样（发送所有人）
        /// </summary>
        /// <param name="message"></param>
        /// <param name="name"></param>
        public void PrivateSend(string message, string name)
        {
            Clients.All.sendPrivateMessage(name, message);
        }

        #endregion

        #region 群聊

        public static ChatContext DbContext = new ChatContext();

        // 重写Hub连接断开的事件  (断线时调用)
        public override Task OnDisconnected(bool stopCalled)
        {
            // 查询用户
            var user = DbContext.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId);

            if (user != null)
            {
                // 删除用户
                DbContext.Users.Remove(user);

                // 从房间中移除用户
                foreach (var item in user.Rooms)
                {
                    RemoveUserFromRoom(item.RoomName);
                }
            }
            return base.OnDisconnected(stopCalled);
        }

        #endregion 

        #region Public Methods

        // 为所有用户更新房间列表
        public void UpdateRoomList()
        {
            var itme = DbContext.Rooms.Select(p => new { p.RoomName });
            var jsondata = JsonHelper.ToJsonString(itme.ToList());
            Clients.All.getRoomlist(jsondata);
        }

        /// <summary>
        /// 加入聊天室
        /// </summary>
        public void JoinRoom(string roomName)
        {
            // 查询聊天室
            var room = DbContext.Rooms.Find(p => p.RoomName == roomName);

            // 存在则加入
            if (room == null) return;

            // 查找房间中是否存在此用户
            var isExistUser = room.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId);

            // 不存在则加入
            if (isExistUser == null)
            {
                var user = DbContext.Users.Find(u => u.UserId == Context.ConnectionId);
                user.Rooms.Add(room);
                room.Users.Add(user);

                // 将客户端的连接ID加入到组里面
                Groups.Add(Context.ConnectionId, roomName);

                //调用此连接用户的本地JS(显示房间)
                Clients.Client(Context.ConnectionId).joinRoom(roomName);
            }
            else
            {
                Clients.Client(Context.ConnectionId).showMessage("请勿重复加入房间!");
            }
        }

        /// <summary>
        /// 创建聊天室
        /// </summary>
        /// <param name="roomName"></param>
        public void CreateRoom(string roomName)
        {
            var room = DbContext.Rooms.Find(a => a.RoomName == roomName);
            if (room == null)
            {
                var cr = new ChatRoom
                {
                    RoomName = roomName
                };

                //将房间加入列表
                DbContext.Rooms.Add(cr);

                // 本人加入聊天室
                JoinRoom(roomName);
                UpdateRoomList();
            }
            else
            {
                Clients.Client(Context.ConnectionId).showMessage("房间名重复!");
            }
        }

        public void RemoveUserFromRoom(string roomName)
        {
            //查找房间是否存在
            var room = DbContext.Rooms.Find(a => a.RoomName == roomName);

            //存在则进入删除
            if (room == null)
            {
                Clients.Client(Context.ConnectionId).showMessage("房间名不存在!");
                return;
            }

            // 查找要删除的用户
            var user = room.Users.FirstOrDefault(a => a.UserId == Context.ConnectionId);
            // 移除此用户
            room.Users.Remove(user);
            //如果房间人数为0,则删除房间
            if (room.Users.Count <= 0)
            {
                DbContext.Rooms.Remove(room);
            }

            Groups.Remove(Context.ConnectionId, roomName);

            //提示客户端
            Clients.Client(Context.ConnectionId).removeRoom("退出成功!");
        }

        /// <summary>
        /// 给房间内所有的用户发送消息
        /// </summary>
        /// <param name="room">房间名</param>
        /// <param name="message">信息</param>
        public void SendMessage(string room, string message)
        {
            // 调用房间内所有客户端的sendMessage方法
            // 因为在加入房间的时候，已经将客户端的ConnectionId添加到Groups对象中了，所有可以根据房间名找到房间内的所有连接Id
            // 其实我们也可以自己实现Group方法，我们只需要用List记录所有加入房间的ConnectionId
            // 然后调用Clients.Clients(connectionIdList),参数为我们记录的连接Id数组。
            Clients.Group(room, new string[0]).sendMessage(room, message + " " + DateTime.Now);
        }

        #endregion

        #region 发送私聊

        /// <summary>
        /// 发送私聊方法
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <param name="message">内容</param>
        /// <param name="userName"></param>
        public void SendPrivateMessage(string userId, string message, string userName)
        {
            #region 指定发送给第3个用户
            #endregion

            // 私发不断线（connectionId 换成userid--可以自己定义）
            Clients.User(userId).receivePrivateMessage(message, userName);

            // 必须用生成的ConnectionId ，断线后。必须在重新生成
            // Clients.Client(ConnectionId).receivePrivateMessage(message);
        }

        #endregion

        #region 离线和上线使用方法

        /// <summary>
        /// 断线时调用
        /// </summary>
        /// <param name="stopCalled"></param>
        /// <returns></returns>
        //public override Task OnDisconnected(bool stopCalled)
        //{
        //    var user = OnlineUsers.FirstOrDefault(u => u.ConnectionId == Context.ConnectionId);

        //    // 判断用户是否存在,存在则删除
        //    if (user == null) return base.OnDisconnected(stopCalled);

        //    Clients.All.onUserDisconnected(user.ConnectionId, user.UserName);   //调用客户端用户离线通知
        //    // 删除用户
        //    OnlineUsers.Remove(user);
        //    return base.OnDisconnected(stopCalled);
        //}

        #endregion

        #region 原有实例（不用管）

        /// <summary>
        /// 供客户端调用的服务器端代码
        /// </summary>
        /// <param name="message"></param>
        public void Send(string message)
        {
            var name = GenerateRandomName(4);

            // 调用所有客户端的sendMessage方法
            Clients.All.sendMessage(name, message);
        }

        #endregion

        #region 暂时无用

        /// <summary>
        /// 登录连线
        /// </summary>
        /// <param name="userId">用户Id</param>
        /// <param name="userName">用户名</param>
        /// <param name="connnectId"></param>
        public void Connect(string userId, string userName)
        {
            var connnectId = Context.ConnectionId;

            if (OnlineUsers.Count(x => x.ConnectionId == connnectId) == 0)
            {
                if (OnlineUsers.Any(x => x.UserId == userId))
                {
                    var items = OnlineUsers.Where(x => x.UserId == userId).ToList();
                    foreach (var item in items)
                    {
                        Clients.AllExcept(connnectId).onUserDisconnected(item.ConnectionId, item.UserName);
                    }
                    OnlineUsers.RemoveAll(x => x.UserId == userId);
                }

                //添加在线人员
                OnlineUsers.Add(new UserInfo
                {
                    ConnectionId = connnectId,
                    UserId = userId,
                    UserName = userName,
                    LastLoginTime = DateTime.Now
                });
            }
            // 所有客户端同步在线用户
            Clients.All.onConnected(connnectId, userName, OnlineUsers);
        }

        /// <summary>
        /// 产生随机用户名函数
        /// </summary>
        /// <param name="length">用户名长度</param>
        /// <returns></returns>
        public static string GenerateRandomName(int length)
        {
            var newRandom = new StringBuilder(62);
            var rd = new Random();
            for (var i = 0; i < length; i++)
            {
                newRandom.Append(Constant[rd.Next(62)]);
            }
            return newRandom.ToString();
        }
        #endregion
    }
}